package com.flux.utils

import android.content.ContentUris
import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.DocumentsContract
import android.provider.MediaStore
import java.io.*

/**
 * 文件工具
 * Created on 2017/12/1.
 *
 * @author Yang
 */
object BaseFileUtil {

    private val DIR_CACHE = File.separator + "cache" + File.separator

    const val FILE_PREFIX = "file://"

    /**
     * Java文件操作 获取文件扩展名
     */
    fun getExtensionName(filename: String?): String? {
        if (filename != null && filename.isNotEmpty()) {
            val dot = filename.lastIndexOf('.')
            if (dot > -1 && dot < filename.length - 1) {
                return filename.substring(dot + 1)
            }
        }
        return filename
    }

    /**
     * Java文件操作 获取不带扩展名的文件名
     */
    fun getFileNameNoEx(filename: String?): String? {
        if (filename != null && filename.isNotEmpty()) {
            val dot = filename.lastIndexOf('.')
            if (dot > -1 && dot < filename.length) {
                return filename.substring(0, dot)
            }
        }
        return filename
    }

    /**
     * 获取缓存文件夹
     *
     * @param context
     * @return
     */
    fun getCacheDir(context: Context): File {
        val sd = getInternalCacheDirectory(context).absolutePath
        val esd = getExternalCacheDirectory(context)?.absolutePath
        if (esd?.isNotEmpty() == true) {
            val dir = File(esd)
            if (!dir.exists()) {
                dir.mkdirs()
            }
            if (dir.exists()) {
                return dir
            }
        }
        if (sd.isNotEmpty()) {
            val dir = File(sd)
            if (!dir.exists()) {
                dir.mkdirs()
            }
            if (dir.exists()) {
                return dir
            }
        }
        val dir = context.cacheDir
        if (!dir.exists()) {
            dir.mkdirs()
        }
        return dir
    }

    /**
     * 获取SD卡缓存目录
     * @param context 上下文
     * @return 缓存目录文件夹 或 null（无SD卡或SD卡挂载失败）
     */
    private fun getExternalCacheDirectory(context: Context): File? {
        var appCacheDir: File? = null
        if (Environment.MEDIA_MOUNTED == Environment.getExternalStorageState()) {
            appCacheDir = context.externalCacheDir

            if (appCacheDir == null) {// 有些手机需要通过自定义目录
                appCacheDir = File(Environment.getExternalStorageDirectory(), "Android/data/" + context.packageName + DIR_CACHE)
            }

            if (!appCacheDir.exists() && !appCacheDir.mkdirs()) {
                LogUtil.e("getExternalDirectory fail ,the reason is make directory fail !")
            }
        } else {
            LogUtil.e("getExternalDirectory fail ,the reason is sdCard nonexistence or sdCard mount fail !")
        }
        return appCacheDir
    }

    /**
     * 获取内存缓存目录
     * @return 缓存目录文件夹 或 null（创建目录文件失败）
     * 注：该方法获取的目录是能供当前应用自己使用，外部应用没有读写权限，如 系统相机应用
     */
    fun getInternalCacheDirectory(context: Context): File {
        val appCacheDir = context.cacheDir// /data/data/app_package_name/cache
        if (!appCacheDir!!.exists() && !appCacheDir.mkdirs()) {
            LogUtil.e("getInternalDirectory fail ,the reason is make directory fail !")
        }
        return appCacheDir
    }

    fun makeDirs(dirName: String): File {
        val dir = File(dirName)
        if (!dir.exists()) {
            dir.mkdirs()
        }
        return dir
    }

    /**
     * 清空文件夹
     */
    fun emptyDir(dir: File?) {
        if (null != dir && dir.exists() && dir.isDirectory) {
            val files = dir.listFiles()
            for (i in files.indices) {
                if (files[i].isDirectory) {
                    emptyDir(files[i])
                }
                files[i].delete()
            }
        }
    }

    /**
     * 从URI获取文件路径
     * @param context 上下文
     * @param uri URI
     * @return 文件路径
     */
    fun getPath(context: Context, uri: Uri): String? {
        // DocumentProvider
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && DocumentsContract.isDocumentUri(context, uri)) {
            // ExternalStorageProvider
            if (isExternalStorageDocument(uri)) {
                val docId = DocumentsContract.getDocumentId(uri)
                val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
                val type = split[0]

                if ("primary".equals(type, ignoreCase = true)) {
                    return Environment.getExternalStorageDirectory().toString() + File.separator + split[1]
                }

            } else if (isDownloadsDocument(uri)) { // DownloadsProvider

                val id = DocumentsContract.getDocumentId(uri)
                val contentUri = ContentUris.withAppendedId(
                        Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id)!!)

                return getDataColumn(context, contentUri, null, null)
            } else if (isMediaDocument(uri)) { // MediaProvider
                val docId = DocumentsContract.getDocumentId(uri)
                val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
                val type = split[0]

                var contentUri: Uri? = null
                when (type) {
                    "image" -> contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
                    "video" -> contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
                    "audio" -> contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
                }

                val selection = "_id=?"
                val selectionArgs = arrayOf(split[1])

                return getDataColumn(context, contentUri, selection, selectionArgs)
            }
        } else if ("content".equals(uri.scheme, true)) { // MediaStore (and general)
            return getDataColumn(context, uri, null, null)
        } else if ("file".equals(uri.scheme, true)) { // File
            return uri.path
        }

        return null
    }

    /**
     * Get the value of the data column for this Uri. This is useful for
     * MediaStore Uris, and other file-based ContentProviders.
     *
     * @param context       The context.
     * @param uri           The Uri to query.
     * @param selection     (Optional) Filter used in the query.
     * @param selectionArgs (Optional) Selection arguments used in the query.
     * @return The value of the _data column, which is typically a file path.
     */
    private fun getDataColumn(context: Context, uri: Uri?, selection: String?,
                              selectionArgs: Array<String>?): String? {

        var cursor: Cursor? = null
        val column = "_data"
        val projection = arrayOf(column)

        try {
            cursor = context.contentResolver.query(uri!!, projection, selection, selectionArgs, null)
            if (cursor != null && cursor.moveToFirst()) {
                val columnIndex = cursor.getColumnIndexOrThrow(column)
                return cursor.getString(columnIndex)
            }
        } finally {
            if (cursor != null)
                cursor.close()
        }
        return null
    }

    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is ExternalStorageProvider.
     */
    private fun isExternalStorageDocument(uri: Uri): Boolean {
        return "com.android.externalstorage.documents" == uri.authority
    }

    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is DownloadsProvider.
     */
    private fun isDownloadsDocument(uri: Uri): Boolean {
        return "com.android.providers.downloads.documents" == uri.authority
    }

    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is MediaProvider.
     */
    private fun isMediaDocument(uri: Uri): Boolean {
        return "com.android.providers.media.documents" == uri.authority
    }
}